#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_event.h"
#include "esp_log.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include "sdkconfig.h"
#include <cJSON.h>
#include "esp_http_client.h"
#include "stdlib.h"
#include<iostream>
#include <bind_utils.h>
using namespace std;
static const char *TAG = "bind";
#define MAX_HTTP_OUTPUT_BUFFER 2048 // http最大数据接收大小
bool gettime = true;                // 是否从网络请求时间
class BindRequest {
public:
    std::string device_id;
    std::string device_key;
    BindRequest(string device_id,string device_key){
        this->device_id = device_id;
        this->device_key = device_key;
    }
    // 序列化为 JSON 字符串
    std::string serializeToJson(char *buf) const {
        cJSON *root = cJSON_CreateObject();
        cJSON_AddStringToObject(root, "device_id", device_id.c_str());
        cJSON_AddStringToObject(root, "device_key", device_key.c_str());
        char *json_str = cJSON_Print(root);
        printf(json_str);
        memcpy(buf, json_str, strlen(json_str));
        // buf[strlen[json_str]] = '\0';
        std::string result(json_str);
        cJSON_Delete(root);
        free(json_str);
        
        return result;
    }

    // 从 JSON 字符串反序列化
    bool deserializeFromJson(const std::string& json) {
        cJSON *root = cJSON_Parse(json.c_str());
        if (root == nullptr) {
            return false;
        }
        cJSON *id = cJSON_GetObjectItem(root, "device_id");
        cJSON *key = cJSON_GetObjectItem(root, "device_key");
        if (id != nullptr && key != nullptr) {
            device_id = id->valuestring;
            device_key = key->valuestring;
        }
        cJSON_Delete(root);
        return true;
    }
};
class Bind{
    public:
        char mac[7];                               //mac地址
        char mac_md5[33];                          //对mac地址进行第一次md5加密
        char mac_md5_md5[33];                      //对mac地址进行第二次md5加密
        char token[128];                           //服务端返回的token，设备id的加密标识
        char post_response[1024];                  //发送绑定请求的返回结果
        const char *msg;                          
        const char *data;
        int16_t code;
        std::string string_mac;                     //string形式的第一次md5加密mac地址
        std::string string_mac_md5;                 //string形式的第二次md5加密mac地址
        std::string post_body;                      //bind  请求体
        std::string post_response_string;           //string形式的返回结果
};
Bind bind_object;
// // 嵌套的 Data 类
// class Data {
// public:
//     std::string id;
//     std::string name;
//     std::string voice_id;
//     std::string device_id;
//     std::string language;
//     std::string character;
//     std::string character_name;
//     std::string character_description;
//     std::string assistant_name;
//     std::string memory;
//     std::string llm_model;
//     std::string mac_address;
//     std::string is_subscribed;
//     std::string token;

//     // 序列化为 JSON 对象
//     cJSON* serializeToJson() const {
//         cJSON *data = cJSON_CreateObject();
//         cJSON_AddStringToObject(data, "id", id.empty() ? nullptr : id.c_str());
//         cJSON_AddStringToObject(data, "name", name.empty() ? nullptr : name.c_str());
//         cJSON_AddStringToObject(data, "voice_id", voice_id.empty() ? nullptr : voice_id.c_str());
//         cJSON_AddStringToObject(data, "device_id", device_id.empty() ? nullptr : device_id.c_str());
//         cJSON_AddStringToObject(data, "language", language.empty() ? nullptr : language.c_str());
//         cJSON_AddStringToObject(data, "character", character.empty() ? nullptr : character.c_str());
//         cJSON_AddStringToObject(data, "character_name", character_name.empty() ? nullptr : character_name.c_str());
//         cJSON_AddStringToObject(data, "character_description", character_description.empty() ? nullptr : character_description.c_str());
//         cJSON_AddStringToObject(data, "assistant_name", assistant_name.empty() ? nullptr : assistant_name.c_str());
//         cJSON_AddStringToObject(data, "memory", memory.empty() ? nullptr : memory.c_str());
//         cJSON_AddStringToObject(data, "llm_model", llm_model.empty() ? nullptr : llm_model.c_str());
//         cJSON_AddStringToObject(data, "mac_address", mac_address.empty() ? nullptr : mac_address.c_str());
//         cJSON_AddStringToObject(data, "is_subscribed", is_subscribed.empty() ? nullptr : is_subscribed.c_str());
//         cJSON_AddStringToObject(data, "token", token.empty() ? nullptr : token.c_str());
//         return data;
//     }

//     // 从 JSON 对象反序列化
//     bool deserializeFromJson(cJSON* data) {
//         id = cJSON_GetObjectItem(data, "id") ? cJSON_GetObjectItem(data, "id")->valuestring : "";
//         name = cJSON_GetObjectItem(data, "name") ? cJSON_GetObjectItem(data, "name")->valuestring : "";
//         voice_id = cJSON_GetObjectItem(data, "voice_id") ? cJSON_GetObjectItem(data, "voice_id")->valuestring : "";
//         device_id = cJSON_GetObjectItem(data, "device_id") ? cJSON_GetObjectItem(data, "device_id")->valuestring : "";
//         language = cJSON_GetObjectItem(data, "language") ? cJSON_GetObjectItem(data, "language")->valuestring : "";
//         character = cJSON_GetObjectItem(data, "character") ? cJSON_GetObjectItem(data, "character")->valuestring : "";
//         character_name = cJSON_GetObjectItem(data, "character_name") ? cJSON_GetObjectItem(data, "character_name")->valuestring : "";
//         character_description = cJSON_GetObjectItem(data, "character_description") ? cJSON_GetObjectItem(data, "character_description")->valuestring : "";
//         assistant_name = cJSON_GetObjectItem(data, "assistant_name") ? cJSON_GetObjectItem(data, "assistant_name")->valuestring : "";
//         memory = cJSON_GetObjectItem(data, "memory") ? cJSON_GetObjectItem(data, "memory")->valuestring : "";
//         llm_model = cJSON_GetObjectItem(data, "llm_model") ? cJSON_GetObjectItem(data, "llm_model")->valuestring : "";
//         mac_address = cJSON_GetObjectItem(data, "mac_address") ? cJSON_GetObjectItem(data, "mac_address")->valuestring : "";
//         is_subscribed = cJSON_GetObjectItem(data, "is_subscribed") ? cJSON_GetObjectItem(data, "is_subscribed")->valuestring : "";
//         token = cJSON_GetObjectItem(data, "token") ? cJSON_GetObjectItem(data, "token")->valuestring : "";
//         return true;
//     }
// };

// // 主 Response 类
// class BindResponse {
// public:
//     int code;
//     std::string message;
//     Data data;

//     // 序列化为 JSON 字符串
//     std::string serializeToJson() const {
//         cJSON *root = cJSON_CreateObject();
//         cJSON_AddNumberToObject(root, "code", code);
//         cJSON_AddStringToObject(root, "message", message.c_str());
//         cJSON_AddItemToObject(root, "data", data.serializeToJson());
//         char *json_str = cJSON_Print(root);
//         std::string result(json_str);
//         cJSON_Delete(root);
//         free(json_str);
//         return result;
//     }

//     // 从 JSON 字符串反序列化
//     bool deserializeFromJson(const std::string& json) {
//         cJSON *root = cJSON_Parse(json.c_str());
//         if (root == nullptr) {
//             return false;
//         }
//         code = cJSON_GetObjectItem(root, "code")->valueint;
//         message = cJSON_GetObjectItem(root, "message")->valuestring;
//         data.deserializeFromJson(cJSON_GetObjectItem(root, "data"));
//         cJSON_Delete(root);
//         return true;
//     }
// };

// 主 Response 类
class BindResponse {
public:
    int code;
    std::string message;
    std::string data;

    // 序列化为 JSON 字符串
    std::string serializeToJson() const {
        cJSON *root = cJSON_CreateObject();
        cJSON_AddNumberToObject(root, "code", code);
        cJSON_AddStringToObject(root, "message", message.c_str());
        cJSON_AddStringToObject(root, "data", data.c_str());
        char *json_str = cJSON_Print(root);
        std::string result(json_str);
        cJSON_Delete(root);
        free(json_str);
        return result;
    }

    // 从 JSON 字符串反序列化
    bool deserializeFromJson(const std::string& json) {
        cJSON *root = cJSON_Parse(json.c_str());
        if (root == nullptr) {
            return false;
        }
        code = cJSON_GetObjectItem(root, "code")->valueint;
        message = cJSON_GetObjectItem(root, "message")->valuestring;
        data=cJSON_GetObjectItem(root,"data")->valuestring;
        cJSON_Delete(root);
        return true;
    }
};
BindResponse bind_response;
esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
    cJSON *pMacAdress = NULL;
#if 0
//switch判断事件代码提示出错可以写成if方式
    switch (evt->event_id)
    {
        case HTTP_EVENT_ERROR:
            ESP_LOGI(TAG, "HTTP_EVENT_ERROR");
            break;
        case HTTP_EVENT_ON_CONNECTED:
            ESP_LOGI(TAG, "HTTP_EVENT_ON_CONNECTED");
            break;
        case HTTP_EVENT_HEADER_SENT:
            ESP_LOGI(TAG, "HTTP_EVENT_HEADER_SENT");
            break;
        case HTTP_EVENT_ON_HEADER:
            ESP_LOGI(TAG, "HTTP_EVENT_ON_HEADER");
            printf("%.*s", evt->data_len, (char *)evt->data);
            break;
        case HTTP_EVENT_ON_DATA:
            ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA,len=%d", evt->data_len);
            if (!esp_http_client_is_chunked_response(evt->client))
            {
                printf("%.*s", evt->data_len, (char *)evt->data);
            }
            break;
        case HTTP_EVENT_ON_FINISH://http完成事件
            ESP_LOGI(TAG, "HTTP_EVENT_ON_FINISH");
            break;
        case HTTP_EVENT_DISCONNECTED://http断开连接事件
            ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
            break;
    }
#endif
    if (evt->event_id == HTTP_EVENT_ON_DATA) // 收到数据事件
    {

        ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA,len=%d", evt->data_len);
        if (!esp_http_client_is_chunked_response(evt->client))
        {
            // evt->data_len
            ESP_LOGI(TAG, "响应:%.*s------",evt->data_len, (char *)evt->data);
            char buf[1024];
            bind_object.code=1;
            memcpy(bind_object.post_response, evt->data, evt->data_len);
            bind_object.post_response_string = bind_object.post_response;
            bind_response.deserializeFromJson(bind_object.post_response_string);
            bind_object.code = bind_response.code;
            bind_object.msg=bind_response.message.c_str();
            bind_object.data=bind_response.data.c_str();
            ESP_LOGI(TAG, "code=%d  msg=%s---  data=%s-- ", bind_object.code, bind_object.msg, bind_object.data);
            set_token_by_nvs(bind_object.data);
            get_token_by_nvs(bind_object.token);
            ESP_LOGI(TAG, "get token--%s--", bind_object.token);
        }
    }
    return ESP_OK;
}


void http_request()
{
    SemaphoreHandle_t bind_ok;
    bind_ok = xSemaphoreCreateCounting(1, 0);
    int flag = 0;
    while (flag==0)
    {
        ESP_LOGI(TAG, "发送http请求");
        char local_response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
        get_mac_address(bind_object.mac);
        md5_encode((char *)bind_object.mac, bind_object.mac_md5);
        //二次加密避免uint8->int8的乱码
        md5_encode((char *)bind_object.mac_md5, bind_object.mac_md5_md5);
        bind_object.string_mac = bind_object.mac_md5;
        bind_object.string_mac_md5 = bind_object.mac_md5_md5;
        BindRequest bind_request(bind_object.string_mac, bind_object.mac_md5_md5);
        bind_object.post_body = "{\"device_id\":\""+bind_object.string_mac+"\",\"device_key\":\""+bind_object.string_mac_md5+"\"}";
        ESP_LOGI(TAG, "post body--%s-=", bind_object.post_body.c_str());
        esp_http_client_config_t config = {
            .url = "http://372cab7b.r12.cpolar.top/api/v1/device/bind",
            .method = HTTP_METHOD_POST, // get方式请求数据
            .event_handler = _http_event_handler,
            .user_data = local_response_buffer,
        };
        esp_http_client_handle_t client = esp_http_client_init(&config);
        esp_http_client_set_header(client, "Content-Type", "application/json");
        esp_http_client_set_post_field(client, bind_object.post_body.c_str(), strlen(bind_object.post_body.c_str()));
        esp_err_t err = esp_http_client_perform(client);
        if (err == ESP_OK)
        {
            ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %d",
                     esp_http_client_get_status_code(client),
                     (int)esp_http_client_get_content_length(client));

            gettime = false;
            flag = 1;
        }
        else
        {
            ESP_LOGI(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
        }

        ESP_LOGI(TAG, "%s\n", local_response_buffer);
        esp_http_client_cleanup(client);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
    vSemaphoreDelete(bind_ok);
}
void http_get_task(void *pvParameters)
{

    http_request();
    while (1)
    {
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}
